//
//  ViewController.m
//  GCDPrePare
//
//  Created by 殷殷明静 on 16/8/17.
//  Copyright © 2016年 殷明静. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()
- (IBAction)async:(id)sender;
- (IBAction)sync:(id)sender;
@property (weak, nonatomic) IBOutlet UIImageView *firstImageView;
@property (weak, nonatomic) IBOutlet UIImageView *secImageView;
@property (weak, nonatomic) IBOutlet UIImageView *image_ymj_1;
@property (weak, nonatomic) IBOutlet UIImageView *image_ymj_2;
@property (weak, nonatomic) IBOutlet UIImageView *image_ymj_3;
@property (weak, nonatomic) IBOutlet UIImageView *image_ymj_4;
@property (nonatomic, strong) NSData *data1;
@property (nonatomic, strong) NSData *data2;
@property (nonatomic, strong) NSData *data3;
@property (nonatomic, strong) NSData *data4;
- (IBAction)downLoadBtn:(id)sender;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}
/**iOS中多线程编程工具主要有：
 
 NSThread
 
 NSOperation
 
 GCD
 
 这三种方法都简单易用,各有千秋.但无疑GCD是最有诱惑力的,因为其本身是apple为多核的并行运算提出的解决方案.虽然当前移动平台用双核的不多,但不影响GCD作为多线程编程的利器(ipad2已经是双核了,这无疑是一个趋势).*/

/**GCD是和block紧密相连的,所以最好先了解下block(可以查看这里).GCD是C level的函数,这意味着它也提供了C的函数指针作为参数,方便了C程序员.*/

/**GCD
 
 全称：Grand Central Dispatch
 
 简介：GCD是对多线程、多核开发较完整的封装。在使用GCD的时候，系统会自动根据CPU使用情况进行调度，所以GCD是
 
 一个简单易用，但是效果很好地多线程多核开发工具。*/

/**教程一涵盖了
 
 1、GCD全局队列的四个优先级
 
 2、几种本文使用到的GCD类型
 
 3、dispatch_async/dispatch_async_f
 
 4、dispatch_sync/dispatch_sync_f*/

/**一、概念与类型
 
 对于GCD来说，所有的执行都放到队列中(queue)，队列的特点是FIFO（先提交的先执行）。
 
 GCD的队列分为几种，主队列（main）,全局队列(global),用户创建队列(create)
 
 对于全局队列，默认有四个，分为四个优先级*/

/**优先级
 
 DISPATCH_QUEUE_PRIORITY_HIGH :优先级最高，在default,和low之前执行
 
 DISPATCH_QUEUE_PRIORITY_DEFAULT 默认优先级，在low之前，在high之后
 
 DISPATCH_QUEUE_PRIORITY_LOW 在high和default后执行
 
 DISPATCH_QUEUE_PRIORITY_BACKGROUND:提交到这个队列的任务会在high优先级的任务和已经提交到background队列的执行完后执行。
 
 官方文档：(the queue is scheduled for execution after all high priority queues have been scheduled and the system runs items on a thread whose priority is set for background status.)*/

/**几种使用到的类型
 
 typealias dispatch_queue_t = NSObject //轻量级的用来描述执行任务的队列
 
 typealias dispatch_block_t = () -> Void //队列执行的闭包(Objective C中的block)
 */

/**几个概念
 
 异步 提交的任务立刻返回，在后台队列中执行
 
 同步 提交的任务在执行完成后才会返回
 
 并行执行（全局队列） 提交到一个队列的任务，比如提交了任务1和任务2，在任务1开始执行，并且没有执行完毕时候，任务2就可以开始执行。
 
 串行执行（用户创建队列） 提交到一个队列中的任务，比如提交了任务1和任务2，只有任务1结束后，任务2才可执行
 */

/**注意：提交到队列中的任务是串行执行，还是并行执行由队列本身决定。*/

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
/**Dispatch Queues
 
 GCD的基本概念就是dispatch queue。dispatch queue是一个对象，它可以接受任务，并将任务以先到先执行的顺序来执行。dispatch queue可以是并发的或串行的。并发任务会像NSOperationQueue那样基于系统负载来合适地并发进行，串行队列同一时间只执行单一任务。
 
 GCD中有三种队列类型：
 
 The main queue: 与主线程功能相同。实际上，提交至main queue的任务会在主线程中执行。main queue可以调用dispatch_get_main_queue()来获得。因为main queue是与主线程相关的，所以这是一个串行队列。
 Global queues: 全局队列是并发队列，并由整个进程共享。进程中存在三个全局队列：高、中（默认）、低三个优先级队列。可以调用dispatch_get_global_queue函数传入优先级来访问队列。
 用户队列: 用户队列 (GCD并不这样称呼这种队列, 但是没有一个特定的名字来形容这种队列，所以我们称其为用户队列) 是用函数 dispatch_queue_create 创建的队列. 这些队列是串行的。正因为如此，它们可以用来完成同步机制, 有点像传统线程中的mutex。*/
/**创建队列
 
 要使用用户队列，我们首先得创建一个。调用函数dispatch_queue_create就行了。函数的第一个参数是一个标签，这纯是为了debug。Apple建议我们使用倒置域名来命名队列，比如“com.dreamingwish.subsystem.task”。这些名字会在崩溃日志中被显示出来，也可以被调试器调用，这在调试中会很有用。第二个参数目前还不支持，传入NULL就行了。*/

- (IBAction)async:(id)sender {
    // 第一个参数是队列的名称，在调试程序时会非常有用，所有尽量不要重名了。
    // 创建一个并行队列
    dispatch_queue_t myQueue = dispatch_queue_create("com.dreamingwish.subsystem.task", DISPATCH_QUEUE_CONCURRENT);
    NSLog(@"%@",myQueue);
    //实际运用中，一般可以用dispatch这样来写，常见的网络请求数据多线程执行模型：
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //子线程中开始网络请求数据
        //更新数据模型
        //异步执行block，函数立即返回
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.lingyu.me/wp-content/uploads/2016/08/www.lingyu.me_20160816042728200.jpg"]];
        dispatch_async(dispatch_get_main_queue(), ^{
            //在主线程中更新UI代码
            _firstImageView.image = [UIImage imageWithData:data];
            
        });
        
    });
}

- (IBAction)sync:(id)sender {
    dispatch_queue_t myQue = dispatch_queue_create("com.dreamyinmingjing.subsystem.task", DISPATCH_QUEUE_SERIAL);
    NSLog(@"%@",myQue);
    dispatch_sync(myQue, ^{
        //同步执行block，函数不返回，一直等到block执行完毕。编译器会根据实际情况优化代码，所以有时候你会发现block其实还在当前线程上执行，并没用产生新线程。
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.lingyu.me/wp-content/uploads/2016/08/www.lingyu.me_20160817090332109.jpg"]];
        
        _secImageView.image = [UIImage imageWithData:data];
    });
}
- (IBAction)downLoadBtn:(id)sender {
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, queue, ^{
        self.data1 = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.lingyu.me/wp-content/uploads/2016/08/www.lingyu.me_20160817090343145.jpg"]];
        NSLog(@"task 1 begin.");

        
        
        NSLog(@"task 1 end.");
        
    });
    dispatch_group_async(group, queue, ^{
        self.data2 = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.lingyu.me/wp-content/uploads/2016/08/www.lingyu.me_20160817090401523.jpg"]];
        NSLog(@"task 2 begin.");

        
        
        NSLog(@"task 2 end.");
        
    });
    dispatch_group_async(group, queue, ^{
        self.data3 = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.lingyu.me/wp-content/uploads/2016/08/www.lingyu.me_20160817090406129.jpg"]];
        NSLog(@"task 3 begin.");

        
        
        NSLog(@"task 3 end.");
        
    });
    dispatch_group_async(group, queue, ^{
        self.data4 = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.lingyu.me/wp-content/uploads/2016/08/www.lingyu.me_20160817090346464.jpg"]];
        NSLog(@"task 4 begin.");

        
        
        NSLog(@"task 4 end.");
        
    });
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"结束了");

        _image_ymj_1.image = [UIImage imageWithData:self.data1];
        _image_ymj_2.image = [UIImage imageWithData:self.data2];
        _image_ymj_3.image = [UIImage imageWithData:self.data3];
        _image_ymj_4.image = [UIImage imageWithData:self.data4];
        
    });
    
}
@end
//http://mobile.51cto.com/iphone-402981.htm
//http://mobile.51cto.com/iphone-402981.htm
